Skip to content

fix: Use a consistent evaluation context for hook invocations and prerequisite evaluations. - #381

Closed
abelonogov-ld wants to merge 2 commits into
mainfrom
andrey/one-flag-read-per-evaluation
Closed

fix: Use a consistent evaluation context for hook invocations and prerequisite evaluations.#381
abelonogov-ld wants to merge 2 commits into
mainfrom
andrey/one-flag-read-per-evaluation

Conversation

@abelonogov-ld

@abelonogov-ld abelonogov-ld commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

There are two primary purposes of this PR.

  1. Access the context once for a variation call and provide that context consistently to prerequisite calls and for the hook meta-data.
  2. Reduce duplication through having an evaluation method that is re-used in each hook invocation site.

Currently the context and the store data are not transactional with each other. So there are limits to the approach, but it is generally an improvement regardless.

The ten variation methods each spelled out the same call to the hook runner
around the same evaluation, and left the flag read to the evaluation itself.
They now collapse onto a helper that does the read, so one place expresses the
order of the read, the hooks and the evaluation, and what an evaluation is
about to return can be described without reading the store a second time.

Co-authored-by: Cursor <cursoragent@cursor.com>
@abelonogov-ld
abelonogov-ld requested a review from a team as a code owner August 11, 2026 02:03

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7efd98c. Configure here.

evaluateWithHooks snapshotted the flag before hooks ran, but
variationDetailInternal still re-read the evaluation context when recording
events. An identify landing in between left the returned value from the prior
context's flag attributed to the new context. Both are now read together and
threaded through the evaluation so the series, the result and the events all
describe one pair.

Co-authored-by: Cursor <cursoragent@cursor.com>
@tanderson-ld

Copy link
Copy Markdown
Contributor

This seems like an improvement, but there are related cases that are not fixed (nor are they trivial to fix). The related cases are a prerequisite graph where a diamond exists. A -> B, A -> C, B -> D, C -> D. I think even with this change, D will be read twice from the store.

A proper fix would be some sort of snapshot of storage, but that is much more involved.

private EvaluationDetail<LDValue> variationDetailInternal(@NonNull String key, @NonNull LDValue defaultValue, boolean checkType, boolean needsReason, Set<String> visited) {
LDContext context = clientContextImpl.getEvaluationContext();
Flag flag = contextDataManager.getNonDeletedFlag(key); // returns null for nonexistent *or* deleted flag
private EvaluationDetail<LDValue> variationDetailInternal(@NonNull String key, @NonNull LDValue defaultValue, boolean checkType, boolean needsReason, Set<String> visited, @Nullable Flag flag, @NonNull LDContext context) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you even need the flag key param now (the first param)? It seems like this function just operates on the domain object Flag and not on the key since the lookup was done beforehand.

@kinyoklion kinyoklion changed the title refactor: read the flag once per evaluation, in one place fix: Use a consistent evaluation context for hook invocations and prerequisite evaluations. Aug 31, 2026
@kinyoklion

Copy link
Copy Markdown
Member

This seems like an improvement, but there are related cases that are not fixed (nor are they trivial to fix). The related cases are a prerequisite graph where a diamond exists. A -> B, A -> C, B -> D, C -> D. I think even with this change, D will be read twice from the store.

A proper fix would be some sort of snapshot of storage, but that is much more involved.

Updated the PR description to note the limitations, but still highlight the value of the change.

@kinyoklion

Copy link
Copy Markdown
Member

This was superseded by PR 380 that contained all the same changes. So I am closing this PR.

@kinyoklion kinyoklion closed this Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants